<?php

namespace app\models\common;

use think\Model;
use think\facade\Validate;
use think\facade\Db;


class OauthClientsModel extends Model
{
    protected $table = 'oauth_clients';


    const CLIENT_TYPE_PASSWORD = 1;
    const CLIENT_TYPE_CLIENT = 2;
    const CLIENT_TYPE_PERSONAL = 3;
    public $clientTypeList = [
        self::CLIENT_TYPE_PASSWORD => '账号密码客户端',
        self::CLIENT_TYPE_CLIENT => '凭证授予客户端',
        self::CLIENT_TYPE_PERSONAL => '个人访问客户端'
    ];

    /**
     * 根据Id获取详细信息
     * @param $id
     * @return array
     */
    public function getInfoById($id)
    {
        $resourcesObj = new OauthResourcesModel();

        $info = self::table($this->table)->where(['id' => $id])->find();
        $info = $info ? $info->toArray() : [];

        if ($info) {
            $info['client_type'] = $this->getClientType($info['personal_access_client'], $info['password_client']);
            $info['type_name'] = isset($this->clientTypeList[$info['client_type']]) ? $this->clientTypeList[$info['client_type']] : '未知';
            $info['resources'] = [];
            if ($info['client_type'] == self::CLIENT_TYPE_CLIENT and $info['resources_ids']) {
                $info['resources'] = $resourcesObj->getRecordList(['ids' => explode(',', $info['resources_ids'])], 0, 0);
            }
            $info['api_key'] = $info['id'];
        }
        return $info;
    }

    /**
     * 根据token获取信息
     * @param $tolen
     * @return array
     */
    public function getInfoByToken($token)
    {

        $info = self::table('oauth_access_tokens')
            ->alias("as t")
            ->join(['oauth_clients' => 'c'], 't.client_id = c.id')
            ->where(['t.id' => ['eq', $token]])
            ->find();
        $info = $info ? $info->toArray() : [];
        return $info;
    }

    /**
     * 获取记录数量
     * @param array $param
     * @return mixed
     */
    public function getRecordCount(array $param = [])
    {
        $pdo = self::table($this->table)
            ->alias("as o");
        $pdo = $this->createSearchParam($pdo, $param);
        return $pdo->count("*");

    }

    /**
     * 获取列表
     * @param $param
     * @param  $page
     * @return mixed
     */
    public function getRecordList(array $param = [], int $start = 0, int $size = 10)
    {

        $field = [
            'o.id',
            'o.name',
            'o.secret',
            'o.personal_access_client',
            'o.password_client'
        ];

        $pdo = self::table($this->table)->field($field);
        $pdo->alias("as o");
        $pdo = $this->createSearchParam($pdo, $param);
        if ($size > 0) {
            $pdo->limit($start, $size);
        }
        $list = $pdo->order('o.created_at', 'asc')->select();
        $list = $list ? $list->toArray() : [];
        foreach ($list as $k => $v) {
            $list[$k]['client_type'] = $this->getClientType($v['personal_access_client'], $v['password_client']);
            $list[$k]['type_name'] = isset($this->clientTypeList[$list[$k]['client_type']]) ? $this->clientTypeList[$list[$k]['client_type']] : '未知';
        }
        return $list;
    }


    /**
     * 获取客户端类型
     * @param $personal_access_client
     * @param $password_client
     * @return int
     * @date 2020-08-12 11:13
     */
    private function getClientType($personal_access_client, $password_client)
    {
        $client_type = 0;
        if ($password_client == 1) {
            $client_type = self::CLIENT_TYPE_PASSWORD;
        }
        if ($personal_access_client == 1) {
            $client_type = self::CLIENT_TYPE_PERSONAL;
        }
        if ($password_client == 0 and $personal_access_client == 0) {
            $client_type = self::CLIENT_TYPE_CLIENT;
        }
        return $client_type;
    }


    /**
     * 获取类型列表
     * @return array
     * @date 2020-08-12 11:02
     */
    public function getTypeList()
    {
        return $this->clientTypeList;
    }

    /**
     * 获取类型名
     * @param $value
     * @return mixed|string
     * @date 2020-08-12 12:06
     */
    public function getTypeName($value)
    {
        $name = isset($this->clientTypeList[$value]) ? $this->clientTypeList[$value] : '未知';
        return $name;
    }

    /**
     * 创建记录
     * @param array $param
     */
    public function createRecord(array $param = [])
    {
        $checkRes = $this->checkSaveData(0, $param);
        if ($checkRes['status'] != STATUS_CODE_SUCCESS) return $checkRes;
        $data = $checkRes['data'];
        $data['created_at'] = $data['updated_at'] = date('Y-m-d H:i:s');
        $res = self::insertGetId($data);
        if (!$res) {
            return funReturn(STATUS_CODE_INSIDEERROR, '添加失败');
        }
        return funReturn(STATUS_CODE_SUCCESS, '添加成功', ['id' => $res]);
    }

    /**
     * 修改数据
     * @param $id
     * @param array $param
     * @return array
     */
    public function updateRecord($id, array $param = [])
    {
        $checkRes = $this->checkSaveData($id, $param);
        if ($checkRes['status'] != STATUS_CODE_SUCCESS) return $checkRes;
        $data = $checkRes['data'];
        $data['updated_at'] = date('Y-m-d H:i:s');
        $res = self::where(['id' => $id])->update($data);
        if ($res === false) {
            return funReturn(STATUS_CODE_INSIDEERROR, '修改失败');
        }
        return funReturn(STATUS_CODE_SUCCESS, '修改成功');
    }

    /**
     * 删除记录
     * @param $id
     * @return array
     */
    public function deleteRecord($id, array $where = [])
    {
        $res = self::where(['id' => $id])->delete();
        if ($res === false) {
            return funReturn(STATUS_CODE_INSIDEERROR, '删除失败');
        }
        return funReturn(STATUS_CODE_SUCCESS, '删除成功');
    }


    /**
     * 组装查询条件
     * @param  $param
     * @param  $pdo
     * @return array
     */
    private function createSearchParam($pdo, array $param = [])
    {
        if (isset($param['id']) && intval($param['id']) > 0) {
            $pdo->where('o.id', '=', $param['id']);
        }

        if (isset($param['personal_access_client']) && (string)$param['personal_access_client'] != '') {
            $pdo->where('o.personal_access_client', '=', $param['personal_access_client']);
        }
        if (isset($param['password_client']) && (string)$param['password_client'] != '') {
            $pdo->where('o.password_client', '=', $param['password_client']);
        }
        if (isset($param['client_type']) && in_array($param['client_type'], array_keys($this->clientTypeList))) {
            $passwordClient = 0;
            $personalAccessClient = 0;

            if ($param['client_type'] == self::CLIENT_TYPE_PASSWORD) $passwordClient = 1;
            if ($param['client_type'] == self::CLIENT_TYPE_PERSONAL) $personalAccessClient = 1;
            $pdo->where('o.personal_access_client', $personalAccessClient)->where('o.password_client', $passwordClient);
        }

        if (isset($param['keywords']) && (string)$param['keywords'] != '') {
            $pdo->where('o.name|o.secret|o.id', 'like', "%{$param['keywords']}%");
        }
        return $pdo;
    }

    /**
     * 校验数据
     * @param $id
     * @param array $params
     * @return array
     */
    private function checkSaveData($id, array $params = [])
    {

        $rule = [
            'name' => 'require|max:50',
            'api_key' => "require|regex:[0-9]{1,6}$|checkApiKey",
            'secret' => 'require|regex:^[A-Za-z0-9]{20,40}$',
        ];

        $message = [
            'name.require' => '名称必须',
            'name.max' => '名称最多50个字符',
            'api_key.require' => 'api_key必须',
            'api_key.regex' => 'api_key格式不合法',
            'api_key.checkApiKey' => 'api_key已存在',
            'secret.require' => 'secret必须',
            'secret.regex' => 'secret格式不合法',
        ];

        $validate = Validate::message($message)->rule($rule);
        $validate->extend('checkApiKey', function ($value) use ($rule, $params, $id) {
            $map1 = [['id', '=', $value]];
            $map2 = [['id', '<>', $id]];
            $exits = Db::table($this->table)->where([$map1, $map2])->find();
            if ($exits) return false;
            return true;
        });

        if (!$validate->check($params)) {
            return funReturn(STATUS_CODE_DATAERROR, $validate->getError());
        }
        $data = [
            'id' => $params['api_key'],
            'name' => $params['name'],
            'secret' => $params['secret']
        ];
        if ($id <= 0) {
            $data['personal_access_client'] = 0;
            $data['password_client'] = 0;
            $data['redirect'] = '';
            $data['revoked'] = 0;
        }
        if (isset($params['resources_ids']) and $params['resources_ids']) {
            $resources = explode(',', $params['resources_ids']);
            $resourcesArr = [];
            foreach ($resources as $v) {
                $v = intval($v);
                if ($v > 0) {
                    array_push($resourcesArr, $v);
                }
            }
            $data['resources_ids'] = implode(',', $resourcesArr);
        }
        return funReturn(STATUS_CODE_SUCCESS, 'success', $data);

    }
}